// eee.Sheffield.PZ.Imaging
//
// Copyright ?Ping Zou, 2007
// sg71.cherub@gmail.com

using System;
using System.Collections.Generic;
using System.Text;
using eee.Sheffield.PZ.Math;
using System.Drawing;
using System.Drawing.Imaging;
namespace eee.Sheffield.PZ.Imaging.ImageFilter
{
    /// <summary>
    /// Discrete Laplacian
    /// L(x, y) = 1 / 4 * (U(x + 1, y) + U(x - 1, y) + U(x, y + 1) + U(x, y - 1)) - U(x, y)
    /// the boundaries of the grid are calculated by extrapolating the second differences from the interior.
    /// </summary>
    public class DiscreteLaplacian : ImageFilter, IGraylevelImageFilter
    {
        #region Fields
        //private string _flag = "[Image -> Gradient -> Discret Laplacian]";        
        #endregion

        #region Constructor
        public DiscreteLaplacian()
        {
            _flag = "[Image -> Gradient -> Discret Laplacian]";
            _normalize = true;
        }
        #endregion
        //#region Properties
        //public string Flag() { return _flag; }
        //public string Log() { return _log; }
        //#endregion

        #region Apply filter
        //public Bitmap ApplyGraylevelImageFilter(Bitmap srcImage) { return Apply(srcImage, out _log); }        
        //public PZMath_matrix ApplyDoubleGraylevelImageFilter(PZMath_matrix srcMatrix) { return ApplyDouble(srcMatrix, out _log); }       
 
        //private Bitmap Apply(Bitmap srcImage, out string logText)
        //{
        //    PZMath_matrix srcMatrix = _converter.ConvertGraylevelBitmapToMatrix(srcImage);
        //    PZMath_matrix dstMatrix = ApplyDouble(srcMatrix, out logText);
        //    Bitmap dstImage = _converter.ConvertMatrixToGraylevelBitmap(dstMatrix, true);
        //    return dstImage;
        //}        

        protected override PZMath_matrix  ApplyDoubleGraylevelImageFilter(PZMath_matrix srcMatrix, out string logText)
        {
            #region source and dst matrix
            // get source
            int width = srcMatrix.ColumnCount;
            int height = srcMatrix.RowCount;

            // create dstMatrix
            PZMath_matrix dstMatrix = new PZMath_matrix(height, width);
            int heightM1 = height - 1;
            int widthM1 = width - 1;
            int heightM2 = height - 2;
            int widthM2 = width - 2;
            #endregion

            #region apply filter
            // for each interior pixel
            for (int y = 1; y < heightM1; y++)
            {
                for (int x = 1; x < widthM1; x++)
                {
                    dstMatrix[y, x] = 1.0 / 4.0 *
                        (srcMatrix[y, x + 1] + srcMatrix[y, x - 1]
                        + srcMatrix[y + 1, x] + srcMatrix[y - 1, x])
                        - srcMatrix[y, x];
                }
            }
            #endregion

            #region extrapolate boundaries
            // upper and bottom boundaries
            for (int x = 1; x < widthM1; x++)
            {
                dstMatrix[0, x] = 2.0 * dstMatrix[1, x] - dstMatrix[2, x];
                dstMatrix[heightM1, x] = 2.0 * dstMatrix[height - 2, x] - dstMatrix[height - 3, x];
            }

            // left and right boundaries
            for (int y = 1; y < heightM1; y++)
            {
                dstMatrix[y, 0] = 2.0 * dstMatrix[y, 1] - dstMatrix[y, 2];
                dstMatrix[y, widthM1] = 2.0 * dstMatrix[y, width - 2] - dstMatrix[y, width - 3];
            }

            // 4 corner
            dstMatrix[0, 0] = 2.0 * dstMatrix[0, 1] - dstMatrix[0, 2];
            dstMatrix[0, widthM1] = 2.0 * dstMatrix[0, width - 2] - dstMatrix[0, width - 3];
            dstMatrix[heightM1, 0] = 2.0 * dstMatrix[heightM1, 1] - dstMatrix[heightM1, 2];
            dstMatrix[heightM1, widthM1] = 2.0 * dstMatrix[heightM1, width - 2] - dstMatrix[heightM1, width - 3];
            #endregion

            logText = "succeds.";
            return dstMatrix;
        } // ApplyDoubleGraylevelImageFilter()


        protected override PZMath_matrix[] ApplyDoubleColourImageFilter(PZMath_matrix[] srcMatrixArray, out string logText)
        {
            #region source and dst matrix
            // get source
            PZMath_matrix srcR = srcMatrixArray[0];
            PZMath_matrix srcG = srcMatrixArray[1];
            PZMath_matrix srcB = srcMatrixArray[2];

            int width = srcR.ColumnCount;
            int height = srcR.RowCount;

            // create dstMatrix
            PZMath_matrix[] dstMatrix = new PZMath_matrix[3];
            dstMatrix[0] = new PZMath_matrix(height, width);
            dstMatrix[1] = new PZMath_matrix(height, width);
            dstMatrix[2] = new PZMath_matrix(height, width);
            PZMath_matrix dstR = dstMatrix[0];
            PZMath_matrix dstG = dstMatrix[1];
            PZMath_matrix dstB = dstMatrix[2];
            int heightM1 = height - 1;
            int widthM1 = width - 1;
            int heightM2 = height - 2;
            int widthM2 = width - 2;
            #endregion

            // TODO DiscretLaplacian::ApplyDouble(PZMath_matrix[])
            dstR.MemCopyFrom(ApplyDoubleGraylevelImageFilter(srcMatrixArray[0], out logText));
            dstG.MemCopyFrom(dstR);
            dstB.MemCopyFrom(dstG);
            logText = "succeds.";
            return dstMatrix;
        } // ApplyDoubleColourImageFilter()
        #endregion


    }
}
